#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "zmipc_proto.h"
#include "debug.h"

const static sproto_header zmipc_header =
{
    .type = ZMIPC_PROTO_TYPE,
    .name = ZMIPC_PROTO_NAME,
    .version = ZMIPC_PROTO_VER,
	.length = sizeof(szmipc_content),
	.build = zmipc_build_package,
	.parse = zmipc_parse_package
};
const sproto_header *zmipc_default_header = &zmipc_header;

static unsigned char cmd_maps[][2] =
{
    // {send-cmd,expect-response-cmd}
// 0x00 indicates no response expected
    {0x85, 0x80}, // device role
    {0x88, 0x84},
    {0x81, 0x87}, // server role
    {0x89, 0x8A},
    {0x8A, 0x8B}, // device role
    {0x8B, 0x00}, // server role
    {0x8C, 0x00} // device role
};
static unsigned char expected_response_cmd(unsigned char cmd)
{
    int size = sizeof(cmd_maps) / 2;
    int res_cmd = 0;
    int i;

    for(i = 0; i < size; i++)
    {
        if(cmd == cmd_maps[i][0])
        {
            res_cmd = cmd_maps[0][1];
            break;
        }
    }

    return res_cmd;
}

// device role: up cmd
static int build_up_package(unsigned int cmd, uzmipc_up_content*content, unsigned char *buff, int *len)
{
    int ret = 0, size = 0, num = 0;
	int i = 0, j = 0;
	unsigned char *ptmp = NULL;
	struct in_addr ip_addr;

    memset(buff, 0, *len);
    memset(&ip_addr, 0, sizeof(struct in_addr));

    switch(cmd)
    {
	case SOCKET_RE_CLIENT_LOGIN:			//0x11
		buff[0] = content->data_transfer.res_login.status;
		buff[1] = content->data_transfer.res_login.frate;
		buff[2] = content->data_transfer.res_login.video_enc;
		buff[3] = content->data_transfer.res_login.audio_enc;
		buff[4] = content->data_transfer.res_login.cbr;
		buff[5] = content->data_transfer.res_login.brate&0xff;
		buff[6] = (content->data_transfer.res_login.brate>>8)&0xff;
		*len = 7;
		break;

	case SOCKET_RES_DATA:				//0x12 -- response data
		buff[0] = content->data_transfer.res_data.type;
		buff[1] = content->data_transfer.res_data.timestamp&0xff;
		buff[2] = (content->data_transfer.res_data.timestamp>>8)&0xff;
		buff[3] = (content->data_transfer.res_data.timestamp>>16)&0xff;
		buff[4] = (content->data_transfer.res_data.timestamp>>24)&0xff;
		buff[5] = (content->data_transfer.res_data.timestamp>>32)&0xff;
		buff[6] = (content->data_transfer.res_data.timestamp>>40)&0xff;
		buff[7] = (content->data_transfer.res_data.timestamp>>48)&0xff;
		buff[8] = (content->data_transfer.res_data.timestamp>>56)&0xff;
		buff[9] = content->data_transfer.res_data.frame_seq;
		size = content->data_transfer.res_data.len;
		memcpy(buff+10,content->data_transfer.res_data.data,size);
		*len = 10+size;
		break;
	
	case SOCKET_UPLOAD_LOG_FILE:		//0x13 //upload log files,add new macro
		buff[0] = content->data_transfer.res_log.sum;
		buff[1] = content->data_transfer.res_log.cur;
		buff[2] = content->data_transfer.res_log.type;
		size = content->data_transfer.res_log.len;
		memcpy(buff+3,content->data_transfer.res_log.data,size);
		*len = 3+size;
		break;
	case SOCKET_RESPONS_AUDIO_DATA:		//0x14
		buff[0] = content->data_transfer.res_audio_req;
		*len = 1;
		break;

	case SOCKET_RES_STOP_SPEECH:		//0x15 -- stop voice-intercom
		// do nothing
		buff[0] = 0xaa;
		*len = 1;
		break;
	
	case SOCKET_SEND_OCX_VERSION:		//0x16
		size = strlen(content->data_transfer.send_pc_ocx_ver);
		memcpy(buff,content->data_transfer.send_pc_ocx_ver,size);
		*len = size;
		break;
	case SOCKET_RE_CLIENT_TYPE:			//0x17
		buff[0] = 0xff;
		*len = 1;
		break;

	// 0x51 0x52 0x54 0x55 0x56 
	case SOCKET_REPORT_ALARM_STATUS:
		buff[0] = content->active_alarm_status.seq;
		buff[1] = content->active_alarm_status.status;
		buff[2] = content->active_alarm_status.extra_stat;
		*len = 3;
		break;
	case SOCKET_RE_FILELIST:
		buff[0] = content->res_sd_file_content.res_sd_file_list.type;
		size = content->res_sd_file_content.res_sd_file_list.size;
		ptmp = content->res_sd_file_content.res_sd_file_list.name_list;
		if(size > 0)
			num = sprintf(buff+1,"%s",ptmp)+1; // add null byte
		else 
			num = 0;
		*len = 1+num;
		break;
	case SOCKET_RE_FILEINFO:
		buff[0] = content->res_sd_file_content.res_sd_file_info.len&0xff;
		buff[1] = (content->res_sd_file_content.res_sd_file_info.len>>8)&0xff;
		buff[2] = (content->res_sd_file_content.res_sd_file_info.len>>16)&0xff;
		buff[3] = (content->res_sd_file_content.res_sd_file_info.len>>24)&0xff;
		buff[4] = content->res_sd_file_content.res_sd_file_info.total_pack&0xff;
		buff[5] = (content->res_sd_file_content.res_sd_file_info.total_pack>>8)&0xff;
		buff[6] = (content->res_sd_file_content.res_sd_file_info.total_pack>>16)&0xff;
		buff[7] = (content->res_sd_file_content.res_sd_file_info.total_pack>>24)&0xff;
		*len = 8;
		break;
	case SOCKET_RE_FILEDATA:
		buff[0] = content->res_sd_file_content.res_sd_file_data.cur_pack&0xff;
		buff[1] = (content->res_sd_file_content.res_sd_file_data.cur_pack>>8)&0xff;
		buff[2] = (content->res_sd_file_content.res_sd_file_data.cur_pack>>16)&0xff;
		buff[3] = (content->res_sd_file_content.res_sd_file_data.cur_pack>>24)&0xff;
		size = content->res_sd_file_content.res_sd_file_data.len;
		memcpy(buff+4,content->res_sd_file_content.res_sd_file_data.data,size);
		*len = 4+size;
		break;
	case SOCKET_RE_DELFILE:
		buff[0] = content->res_sd_file_content.res_sd_del_file;
		*len = 1;
		break;
	// end add
	
	case SOCKET_RE_PTZ_CMD:				//0x57 // add new macro
		buff[0] = content->res_ptz_ctrl.status;
		buff[1] = content->res_ptz_ctrl.reason;
		*len = 2;
		break;
	case SOCKET_RE_IMAGE:				//0x58
		buff[0] = content->res_image_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_image_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_image_params.bright;
			if(content->res_image_params.hue >= 0)
			{
				buff[2] = content->res_image_params.hue;
				buff[3] = 0;
			}
			else
			{
				buff[2] = content->res_image_params.hue;
				buff[3] = 1;
			}
			buff[4] = content->res_image_params.saturation;
			buff[5] = content->res_image_params.contrast;
			buff[6] = content->res_image_params.mirror;
			buff[7] = content->res_image_params.up_res_sensor_type;
			buff[8] = content->res_image_params.wdflag;
			*len = 9;
		}
		break;

	case SOCKET_RE_VIDEO:				//0xC0
		buff[0] = content->res_video_params.up_res_status;
		*len = 1; // when set
		if((ZMIPC_ACT_GET == content->res_video_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_video_params.stream_type;
			buff[2] = content->res_video_params.resolution;
			buff[3] = content->res_video_params.frate;
			buff[4] = content->res_video_params.gop;
			buff[5] = content->res_video_params.cbr;//venc_type;
			buff[6] = content->res_video_params.brate&0xff;
			buff[7] = (content->res_video_params.brate>>8)&0xff;
			buff[8] = content->res_video_params.image_level;
			buff[9] = content->res_video_params.up_res_sensor_type;
			*len = 10;
		}
		break;
	case SOCKET_RE_RECODER:				//0xC1
		buff[0] = content->res_record_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_record_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_record_params.flag;
			buff[2] = content->res_record_params.duration;
			buff[3] = content->res_record_params.audio_flag;
			*len = 4;
		}
		break;
	case SOCKET_RE_OSD:					//0xC2
		buff[0] = content->res_osd_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_osd_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_osd_params.time_flag;
			buff[2] = content->res_osd_params.osd_flag;
			num = sprintf(buff+3,"%s",content->res_osd_params.osd_info);
			*len = 3+num+1;
		}
		break;
	case SOCKET_RE_NET:					//0xC3
		buff[0] = content->res_network_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_network_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			if((ret=inet_aton(content->res_network_params.ip,&ip_addr))!=0)
			{
				ptmp = (unsigned char *)&ip_addr.s_addr;
				memcpy(buff+1,ptmp,4);
			}
			if((ret!=0)&&(ret=inet_aton(content->res_network_params.mask,&ip_addr))!=0)
			{
				ptmp = (unsigned char *)&ip_addr.s_addr;
				memcpy(buff+5,ptmp,4);
			}
			if((ret!=0)&&(ret=inet_aton(content->res_network_params.gateway,&ip_addr))!=0)
			{
				ptmp = (unsigned char *)&ip_addr.s_addr;
				memcpy(buff+9,ptmp,4);
			}
			if((ret!=0)&&(ret=inet_aton(content->res_network_params.dns1,&ip_addr))!=0)
			{
				ptmp = (unsigned char *)&ip_addr.s_addr;
				memcpy(buff+13,ptmp,4);
			}
			if((ret!=0)&&(ret=inet_aton(content->res_network_params.dns2,&ip_addr))!=0)
			{
				ptmp = (unsigned char *)&ip_addr.s_addr;
				memcpy(buff+17,ptmp,4);
			}
			if(ret != 0)
			{
				buff[21] = content->res_network_params.web_port&0xff;
				buff[22] = (content->res_network_params.web_port>>8)&0xff;
				buff[23] = content->res_network_params.video_port&0xff;
				buff[24] = (content->res_network_params.video_port>>8)&0xff;
				buff[25] = content->res_network_params.rtsp_port&0xff;
				buff[26] = (content->res_network_params.rtsp_port>>8)&0xff;
				buff[27] = content->res_network_params.upnp_flag;
				buff[28] = content->res_network_params.dhcp_flag;
			}
			if(ret != 0)
			{
				*len = 29;
				ret = VPI_SUCCESS;
			}
			else
			{
				PLOG(ERR,"inet_aton error,some ipaddr is invalid!\n");
				ret = VPI_EPARAMS;
			}
		}
		break;
	case SOCKET_RE_WIFI:					//0xC4
		buff[0] = content->res_wifi_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_wifi_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_wifi_params.flag;
			buff[2] = content->res_wifi_params.auth_flag;
			buff[3] = content->res_wifi_params.auth_type;
			buff[4] = content->res_wifi_params.status;
			num = 0;
			num += sprintf(buff+5,"%s",content->res_wifi_params.password);
			buff[5+num] = 0x20;
			num += 1;
			num += sprintf(buff+5+num,"%s",content->res_wifi_params.name);
			buff[5+num] = 0x20;
			num += 1;// include null bytes

			buff[5+num] = content->res_wifi_params.group_auth_type&0x0f;
			buff[5+num] |= (content->res_wifi_params.pairwise_type<<4);
			num += 1;
			buff[5+num] = content->res_wifi_params.wep_auth_type;
			num += 1;
			buff[5+num] = content->res_wifi_params.wep_key_format;
			num += 1;

			for(i=0;i<4;i++)
			{
				num += sprintf(buff+5+num,"%s",content->res_wifi_params.wep_password[i]);
				buff[5+num] = 0x20;
				num += 1;
			}
			buff[5+num-1] = 0;// reset last 0x20 to 0x00(null byte)
			*len = 5+num;
		}
		break;
	case SOCKET_RE_WIFI_LIST:			//0xC5
		size = content->res_wifi_list.size;
		num = 0;
		for(i=0;i<size;i++)
		{
			j = 9*i+num;
			sscanf(content->res_wifi_list.wifi_list[i].mac_addr, \
					"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", \
			&buff[0+j],&buff[1+j],&buff[2+j],&buff[3+j],&buff[4+j],&buff[5+j]);
			buff[6+j] = content->res_wifi_list.wifi_list[i].auth_type;
			buff[7+j] = content->res_wifi_list.wifi_list[i].signal_value;
			buff[8+j] = content->res_wifi_list.wifi_list[i].group_auth_type&0x0f;
			buff[8+j] |= (content->res_wifi_list.wifi_list[i].pairwise_type<<4);
			num += sprintf(buff+9+j,"%s;",content->res_wifi_list.wifi_list[i].wifi_ssid);
		}
		*len = 9*size+num;
		break;
	case SOCKET_RE_DEFAULT_SET:			//0xC6
		buff[0] = content->res_restore_factory;
		*len = 1;
		break;
	case SOCKET_RE_TIME_SET:			//0xC7
		buff[0] = content->res_time_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_time_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_time_params.year-2000;
			buff[2] = content->res_time_params.month;
			buff[3] = content->res_time_params.mday;
			buff[4] = content->res_time_params.hour;
			buff[5] = content->res_time_params.mins;
			buff[6] = content->res_time_params.secs;
			buff[7] = content->res_time_params.ntp_flag;
			buff[8] = content->res_time_params.tz;
			num = sprintf(buff+9,"%s",content->res_time_params.ntp_server);
			num += 1;
			*len = 9+num;
		}
		break;
	case SOCKET_RE_MD_SET:				//0xC8
		buff[0] = content->res_md_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_md_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_md_params.flag;
			for(i=0;i<6;i++)
			{
				buff[i+2] = content->res_md_params.group_flag[i];
				buff[i+2+6] = content->res_md_params.group_attr[i];
				buff[i+2+12] = content->res_md_params.group_sens[i];
				buff[i+2+18] = content->res_md_params.group_delay[i];
				buff[i+2+24] = content->res_md_params.group_priority[i];
			}
			for(i=0;i<6;i++)
			{
				j = 32+i*8;
				buff[j+0] = content->res_md_params.group_coord[i].x[0]&0xff;
				buff[j+1] = (content->res_md_params.group_coord[i].x[0]>>8)&0xff;
				buff[j+2] = content->res_md_params.group_coord[i].x[1]&0xff;
				buff[j+3] = (content->res_md_params.group_coord[i].x[1]>>8)&0xff;
				buff[j+4] = content->res_md_params.group_coord[i].y[0]&0xff;
				buff[j+5] = (content->res_md_params.group_coord[i].y[0]>>8)&0xff;
				buff[j+6] = content->res_md_params.group_coord[i].y[1]&0xff;
				buff[j+7] = (content->res_md_params.group_coord[i].y[1]>>8)&0xff;
			}
			*len = 32+48;
		}
		break;
	case SOCKET_RE_POLICE_RECODE_SET:	//0xC9
		buff[0] = content->res_alarm_params.record_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_alarm_params.record_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_alarm_params.record_params.flag;
			buff[2] = content->res_alarm_params.record_params.duration&0xff;
			buff[3] = (content->res_alarm_params.record_params.duration>>8)&0xff;
			*len = 4;
		}
		break;
	case SOCKET_RE_POLICE_EMAILE_SET:	//0xCA
		buff[0] = content->res_alarm_params.email_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_alarm_params.email_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_alarm_params.email_params.flag;
			for(i=0;i<5;i++)
				memcpy(buff+2+i*64,content->res_alarm_params.email_params.receiver[i],64);
			memcpy(buff+2+i*64,content->res_alarm_params.email_params.smtp_server,32);
			i = 2+5*64+32;
			buff[i] = content->res_alarm_params.email_params.smtp_port&0xff;
			buff[i+1] = (content->res_alarm_params.email_params.smtp_port>>8)&0xff;
			buff[i+2] = content->res_alarm_params.email_params.safe_type;
			buff[i+3] = content->res_alarm_params.email_params.check_flag;
			memcpy(buff+i+4,content->res_alarm_params.email_params.smtp_user,64);
			memcpy(buff+i+4+64,content->res_alarm_params.email_params.smtp_code,64);
			*len = 7*64+32+6;
		}
		break;
	case SOCKET_RE_POLICE_FTP_SET:		//0xCB
		buff[0] = content->res_alarm_params.ftp_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_alarm_params.ftp_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_alarm_params.ftp_params.flag;
			memcpy(buff+2,content->res_alarm_params.ftp_params.ftp_server,64);
			i = 2+64;
			buff[i] = content->res_alarm_params.ftp_params.ftp_port&0xff;
			buff[i+1] = (content->res_alarm_params.ftp_params.ftp_port>>8)&0xff;
			i += 2;
			memcpy (buff + i, content->res_alarm_params.ftp_params.down_ftp_user, 64);
			i += 64;
			memcpy (buff + i, content->res_alarm_params.ftp_params.down_ftp_code, 32);
			i += 32;
			buff[i+2] = content->res_alarm_params.ftp_params.mode;
			memcpy(buff+i+3,content->res_alarm_params.ftp_params.ftp_updir,128);
			*len = 5+64+64+32+128;
		}
		break;
	case SOCKET_RE_POLICE_PICTURE_SET:	//0xCC
		buff[0] = content->res_alarm_params.snapshot_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_alarm_params.snapshot_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_alarm_params.snapshot_params.flag;
			buff[2] = content->res_alarm_params.snapshot_params.pics_num&0xff;
			buff[3] = (content->res_alarm_params.snapshot_params.pics_num>>8)&0xff;
			buff[4] = content->res_alarm_params.snapshot_params.interval_time;
			*len = 5;
		}
		break;
	case SOCKET_RE_POLICE_IO_SET:	   	//0xCD
		buff[0] = content->res_alarm_params.io_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_alarm_params.io_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_alarm_params.io_params.flag;
			buff[2] = content->res_alarm_params.io_params.trig_level;
			*len = 3;
		}
		break;

	case SOCKET_RE_MAILTEST:			// 0xCE -- response mail test result
		buff[0] = content->res_mail_test.result;
		buff[1] = content->res_mail_test.err_code&0xff;
		buff[2] = (content->res_mail_test.err_code>>8)&0xff;
		*len = 3;
		break;
	
	case SOCKET_RE_SET_CODE:			//0xCF
		buff[0] = content->res_change_password.result;
		buff[1] = content->res_change_password.err_code&0xff;
		buff[2] = (content->res_change_password.err_code>>8)&0xff;
		*len = 3;
		break;
	case SOCKET_RE_NATTYPE:				//0xD0
		buff[0] = content->res_nat_type.nat_type;
		buff[1] = content->res_nat_type.route_loop;
		num = sprintf(buff+2,"%s",content->res_nat_type.id);
		*len = 2+num;
		break;
	/* 
	 * //register cmd,in p2p proto
	 * case SOCKET_GET_SERVERINFO  		//0xD2  
	 */
	case SOCKET_RE_IO_CONTROL:			// 0xD6 -- IO control cmd reponse
		buff[0] = content->res_io_control;
		*len = 1;
		break;
	case SOCKET_RE_MINOR_STREAM:		//0xD7 // response to 0xB4 cmd
		buff[0] = content->res_minor_stream.result;
		buff[1] = content->res_minor_stream.level;
		*len = 2;
		break;
	case SOCKET_SEND_PASSWD:			//0xD8 // unkown
		*len = 0;
		break;
	case SOCKET_RE_SDCARD: 			//0xFFA1  //lhq add
		buff[0] = content->res_sdcard_params.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_sdcard_params.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			buff[1] = content->res_sdcard_params.umount_flag;
			buff[2] = content->res_sdcard_params.free_space & 0xff;
			buff[3] = (content->res_sdcard_params.free_space >> 8) & 0xff;
			buff[4] = (content->res_sdcard_params.free_space >> 8) & 0xff;
			buff[5] = (content->res_sdcard_params.free_space >> 8) & 0xff;
			buff[6] = content->res_sdcard_params.total_space & 0xff;
			buff[7] = (content->res_sdcard_params.total_space >> 8) & 0xff;
			buff[8] = (content->res_sdcard_params.total_space >> 8) & 0xff;
			buff[9] = (content->res_sdcard_params.total_space >> 8) & 0xff;
			*len = 10;
		}
		break;
	case SOCKET_RE_DEV_VERSION:			//0xFFB7  //lhq add
		buff[0] = content->res_dev_version.up_res_status;
		*len = 1;
		if((ZMIPC_ACT_GET == content->res_dev_version.down_action)
			&& (buff[0] == ZMIPC_RES_SUCCESS))
		{
			memcpy(&buff[1], content->res_dev_version.version, 16);
			*len = 17;
		}
		break;
		
	case SOCKET_RES_SET_WIFI_IN_AP: 
		buff[0] = content->res_ap_wifi.sta;
		num = sprintf(&buff[1], "%s", content->res_ap_wifi.ssid);
		*len = num + 1;
		break;
    default:
		PLOG(ERR,"cmd[0x%02x] is invalid\n",cmd);
        ret = VPI_EFAIL;
        break;
    }

    return ret;
}

// PC role: down cmd
static int build_down_package(unsigned int cmd, uzmipc_down_content*content, unsigned char *buff, int *len)
{
    int ret = 0,size = 0;
	//char *ptmp = NULL;
    memset(buff, 0, *len);

    switch(cmd)
    {
	// TODO... server
	case SOCKET_CLIENT_LOGIN: //0x01
		size = content->data_transfer.login_passwd.len;
		memcpy(buff,content->data_transfer.login_passwd.password,size);
		*len = size;
		break;
	case SOCKET_REQUEST_SD_TOP:			//0x43
		buff[0] = content->sd_file_content.sd_file_list.type;
		if(buff[0] == ZMIPC_SD_DIRLIST)
			memset(buff+1,0x30,8);
		else
			strncpy(buff+1,content->sd_file_content.sd_file_list.dirname,8);
		*len = 9;
		break;
	case SOCKET_REQUEST_SD_FILE_INFO:	//0x44
		strncpy(buff,content->sd_file_content.sd_fileinfo_trans.date,8);
		strncpy(buff+8,content->sd_file_content.sd_fileinfo_trans.fname,6);
		buff[14] = content->sd_file_content.sd_fileinfo_trans.size&0xff;
		buff[15] = (content->sd_file_content.sd_fileinfo_trans.size>>8)&0xff;
		*len = 16;
		break;
	case SOCKET_DEL_SD_FILE:			//0x45
		strncpy(buff,content->sd_file_content.sd_del_file.date,8);
		strncpy(buff+8,content->sd_file_content.sd_del_file.fname,6);
		*len = 14;
		break;
    default:
        ret = VPI_EFAIL;
        break;
    }

    return ret;
}

// server role
static int parse_up_package(unsigned int cmd, uzmipc_up_content*content, unsigned char *buff, int len)
{
    int ret = 0;

	memset(content,0,sizeof(uzmipc_up_content));
    switch(cmd)
    {
	// TODO... server
    default:
        ret = VPI_EFAIL;
        break;
    }

    return ret;
}

// device role work
static int parse_down_package(unsigned int cmd, uzmipc_down_content*content, unsigned char *buff, int len)
{
    int ret = 0;
	int i = 0, j = 0, k = 0;
	unsigned char ck_sum = buff[len];///!preserve checksum to restore it  
	//char *ptmp = NULL;

	memset(content,0,sizeof(uzmipc_down_content));
    switch(cmd)
	{
		// device-role
		case SOCKET_CLIENT_LOGIN: //0x01- request login device
			memcpy(content->data_transfer.login_passwd.password,buff,len);
			content->data_transfer.login_passwd.len = len;
			break;
		case SOCKET_DATA_TYPE:				//0x02
			content->data_transfer.data_type = buff[0];
			break;
		case SOCKET_GET_LOG:				//0x03
			content->data_transfer.get_log_file.type = buff[0];
			content->data_transfer.get_log_file.size = buff[1]|(buff[2]<<8);
			break;
		case SOCKET_REQ_SEND_AUDIO:			//0x04
			// do nothing
			// content->data_transfer.req_audio_dummy = 0;
			break;
		case SOCKET_SEND_AUDIO:				//0x05
			content->data_transfer.send_audio_data.data = buff;
			content->data_transfer.send_audio_data.len = len;
			break;
		case SOCKET_STOP_RECV_AUDIO:		//0x06
			content->data_transfer.stop_data_type = buff[0];
			break;

		case SOCKET_MULTIWAY_DATA:			// 0x07,DVR use it
			content->data_transfer.req_multichn_data.type = buff[0];
			content->data_transfer.req_multichn_data.chnnl = buff[1];
			break;

		case SOCKET_GET_CLINET_TYPE:		//0x08
			content->data_transfer.send_client_type = buff[0];
			break;

			/* Control CMD Part */
		case SOCKET_GET_ALARM_STATUS:		//0x41
			// do nothing
			break;
		case SOCKET_CLEAN_ALARM_STATUS:		//0x42
			// do nothing
			break;
		case SOCKET_REQUEST_SD_TOP:			//0x43
			content->sd_file_content.sd_file_list.type = buff[0];
			strncpy(content->sd_file_content.sd_file_list.dirname,buff+1,8);
			content->sd_file_content.sd_file_list.dirname[8] = 0;
			break;
		case SOCKET_REQUEST_SD_FILE_INFO:	//0x44
			strncpy(content->sd_file_content.sd_fileinfo_trans.date,buff,8);
			content->sd_file_content.sd_fileinfo_trans.date[8] = 0;
			strncpy(content->sd_file_content.sd_fileinfo_trans.fname,buff+8,6);
			content->sd_file_content.sd_fileinfo_trans.fname[6] = 0;
			content->sd_file_content.sd_fileinfo_trans.size = buff[14]|(buff[15]<<8);
			break;
		case SOCKET_DEL_SD_FILE:			//0x45
			content->sd_file_content.sd_del_file.date[0] = 0;
			content->sd_file_content.sd_del_file.fname[0] = 0;
			if(len >= 8)
			{
				strncpy(content->sd_file_content.sd_del_file.date,buff,8);
				content->sd_file_content.sd_del_file.date[8] = 0;
			}
			if(len >= 14)
			{
				strncpy(content->sd_file_content.sd_del_file.fname,buff+8,6);
				content->sd_file_content.sd_del_file.fname[6] = 0;
			}
			break;
		case SOCKET_PTZ_CTRL:				//0x46
			content->ptz_ctrl_content.action = buff[0];
			content->ptz_ctrl_content.step = buff[1];
			content->ptz_ctrl_content.speed = buff[2];
			content->ptz_ctrl_content.stand_time = buff[3];
			content->ptz_ctrl_content.preset_index = buff[4];
			content->ptz_ctrl_content.index_a = buff[5];
			content->ptz_ctrl_content.index_b = buff[6];
			break;

		case SOCKET_REQUEST_SD_FILE_DATA:	//0x48
			content->sd_file_content.sd_filedata_packnum = buff[0]|(buff[1]<<8);
			break;

		case SOCKET_IMAGE_VALUE:			//0x49
			content->image_params_operation.down_action = buff[0];
			if(buff[0] == ZMIPC_ACT_SET)
			{
				content->image_params_operation.bright = buff[1];
				content->image_params_operation.hue = buff[3]?(-1)*buff[2]:buff[2];
				content->image_params_operation.saturation = buff[4];
				content->image_params_operation.contrast = buff[5];
				content->image_params_operation.mirror = buff[6];
				content->image_params_operation.wdflag = buff[7];
			}
			break;
		case SOCKET_VIDEO_VALUE:			//0x50
			content->video_params_operation.down_action = buff[0];
			if(buff[0] == ZMIPC_ACT_SET)
			{
				content->video_params_operation.stream_type = buff[1];
				content->video_params_operation.resolution = buff[2];
				content->video_params_operation.frate = buff[3];
				content->video_params_operation.gop = buff[4];
				content->video_params_operation.cbr = buff[5]; // venc_type
				content->video_params_operation.brate = buff[6]|(buff[7]<<8);
				content->video_params_operation.image_level = buff[8];
			}
			break;

		case SOCKET_RECODER_VALUE: 			//0xA0
			content->record_params_operation.down_action = buff[0];
			if(buff[0] == ZMIPC_ACT_SET)
			{
				content->record_params_operation.flag = buff[1];
				content->record_params_operation.duration = buff[2];
				content->record_params_operation.audio_flag = buff[3];
			}
			break;
		case SOCKET_OSD_VALUE:				//0xA1
			content->osd_params_operation.down_action = buff[0];
			if(buff[0] == ZMIPC_ACT_SET)
			{
				content->osd_params_operation.time_flag = buff[1];
				content->osd_params_operation.osd_flag = buff[2];
				strncpy(content->osd_params_operation.osd_info,buff+3,18);
				content->osd_params_operation.osd_info[18] = 0;
			}
			break;
		case SOCKET_NET_VALUE:				//0xA2
			content->network_params_operation.down_action = buff[0];
			if(buff[0] == ZMIPC_ACT_SET)
			{
				sprintf(content->network_params_operation.ip,"%u.%u.%u.%u",
						buff[1],buff[2],buff[3],buff[4]);
				sprintf(content->network_params_operation.mask,"%u.%u.%u.%u",
						buff[5],buff[6],buff[7],buff[8]);
				sprintf(content->network_params_operation.gateway,"%u.%u.%u.%u",
						buff[9],buff[10],buff[11],buff[12]);
				sprintf(content->network_params_operation.dns1,"%u.%u.%u.%u",
						buff[13],buff[14],buff[15],buff[16]);
				sprintf(content->network_params_operation.dns2,"%u.%u.%u.%u",
						buff[17],buff[18],buff[19],buff[20]);
				content->network_params_operation.web_port = buff[21]|(buff[22]<<8);
				content->network_params_operation.video_port = buff[23]|(buff[24]<<8);
				content->network_params_operation.rtsp_port = buff[25]|(buff[26]<<8);
				content->network_params_operation.upnp_flag = buff[27];
				content->network_params_operation.dhcp_flag = (buff[28]==1)?ZMIPC_FLAG_ON:ZMIPC_FLAG_OFF;
			}
			break;
		case SOCKET_WIFI_VALUE:				//0xA3
			content->wifi_params_operation.down_action = buff[0];
			if(buff[0] == ZMIPC_ACT_SET)
			{
				content->wifi_params_operation.flag = buff[1];
				content->wifi_params_operation.auth_flag = buff[2];
				content->wifi_params_operation.auth_type = buff[3];
				content->wifi_params_operation.status = buff[4];
				content->wifi_params_operation.group_auth_type = buff[5]&0x0f;
				content->wifi_params_operation.pairwise_type = (buff[5]>>4)&0x0f;
				content->wifi_params_operation.wep_auth_type = buff[6];
				content->wifi_params_operation.wep_key_format = buff[7];
				j = 8;
				for(k = 0; k < 4;k++)
				{
					for(i=0;(buff[j+i]!=0x20)&(i<32);i++)
						content->wifi_params_operation.wep_password[k][i]=buff[j+i];
					content->wifi_params_operation.wep_password[k][i]=0;
					j = j+i+1;
				}
				for(i=0;(buff[j+i]!=0x20)&(i<32);i++)
					content->wifi_params_operation.password[i] = buff[j+i];
				content->wifi_params_operation.password[i] = 0;
				j = j+i+1;
				for(i=0;((j+i)<len)&(i<32);i++)
					content->wifi_params_operation.name[i] = buff[j+i];
				content->wifi_params_operation.name[i] = 0;
			}
			break;
		case SOCKET_WIFI_LIST:				//0xA4
			// do nothing
			content->get_wifi_list_dummy = buff[0];// should be '0xff'
			break;
		case SOCKET_DEFAULT_SET:			//0xA5
			// do nothing
			content->restore_factory_set_dummy = buff[0];// should be '0xff'
			break;
		case SOCKET_TIME_SET:				//0xA6
			content->time_params_operation.down_action = buff[0];
			if((buff[0] == ZMIPC_ACT_SET) || (buff[0] == ZMIPC_ACT_SET+1))
			{// set time or set ntp
				content->time_params_operation.year = 2000+buff[1];
				content->time_params_operation.month = buff[2];
				content->time_params_operation.mday = buff[3];
				content->time_params_operation.hour = buff[4];
				content->time_params_operation.mins = buff[5];
				content->time_params_operation.secs = buff[6];
				content->time_params_operation.ntp_flag = buff[7];
				content->time_params_operation.tz = buff[8];
				strncpy(content->time_params_operation.ntp_server,buff+9,len-9);
			}
			break;
		case SOCKET_SET_ALARM_MD:			//0xA7
			content->md_params_operation.down_action = buff[0];
			if(buff[0] == ZMIPC_ACT_SET)
			{
				content->md_params_operation.flag = buff[1];
				for(i=0;i<6;i++)
				{
					content->md_params_operation.group_flag[i]  = buff[i+2];    
					content->md_params_operation.group_attr[i]  = buff[i+2+6];  
					content->md_params_operation.group_sens[i]  = buff[i+2+12]; 
					content->md_params_operation.group_delay[i]  = buff[i+2+18];  
					content->md_params_operation.group_priority[i] = buff[i+2+24]; 
				}
				for(i=0;i<6;i++)
				{
					j = 32+i*8;
					content->md_params_operation.group_coord[i].x[0]= buff[j+0]|(buff[j+1]<<8);
					content->md_params_operation.group_coord[i].x[1]= buff[j+2]|(buff[j+3]<<8);
					content->md_params_operation.group_coord[i].y[0]= buff[j+4]|(buff[j+5]<<8);
					content->md_params_operation.group_coord[i].y[1]= buff[j+6]|(buff[j+7]<<8);
				}
			}
			break;

	case SOCKET_HOLD_HEART:				// A8 -- heart cmd to hold connection
		content->heart_pack_dummy = buff[0];//should be '0xaa'
		break;
	
	case SOCKET_SET_ALARM_REC:			//0xA9
		content->alarm_params_operation.record_params.down_action = buff[0];
		if(buff[0] == ZMIPC_ACT_SET)
		{
			content->alarm_params_operation.record_params.flag = buff[1];
			content->alarm_params_operation.record_params.duration = buff[2]|(buff[3]<<8);
		}
		break;
	case SOCKET_SET_ALARM_EMAIL:		//0xAA
		content->alarm_params_operation.email_params.down_action = buff[0];
		if(buff[0] == ZMIPC_ACT_SET)
		{
			content->alarm_params_operation.email_params.flag = buff[1];
			for(i=0;i<5;i++)
				memcpy(content->alarm_params_operation.email_params.receiver[i],buff+2+i*64,64);
			memcpy(content->alarm_params_operation.email_params.smtp_server,buff+2+i*64,32);
			i = 2+5*64+32;
			content->alarm_params_operation.email_params.smtp_port = buff[i]+(buff[i+1]<<8);
			content->alarm_params_operation.email_params.safe_type = buff[i+2];
			content->alarm_params_operation.email_params.check_flag = buff[i+3];
			memcpy(content->alarm_params_operation.email_params.smtp_user,buff+i+4,64);
			memcpy(content->alarm_params_operation.email_params.smtp_code,buff+i+4+64,64);
		}
		break;
	case SOCKET_SET_ALARM_FTP:			//0xAB
		content->alarm_params_operation.ftp_params.down_action = buff[0];
		if(buff[0] == ZMIPC_ACT_SET)
		{
			content->alarm_params_operation.ftp_params.flag = buff[1];
			memcpy(content->alarm_params_operation.ftp_params.ftp_server,buff+2,64);
			i = 2+64;
			content->alarm_params_operation.ftp_params.ftp_port = buff[i] + (buff[i+1]<<8);
			memcpy(content->alarm_params_operation.ftp_params.down_ftp_user,buff+i+2,64);
			memcpy(content->alarm_params_operation.ftp_params.down_ftp_code,buff+i+2+64,32);
			i += 2+64+32;
			content->alarm_params_operation.ftp_params.mode = buff[i];
			memcpy(content->alarm_params_operation.ftp_params.ftp_updir,buff+i+1,128);
		}
		break;
	case SOCKET_SET_ALARM_SNAP:			//0xAC
		content->alarm_params_operation.snapshot_params.down_action = buff[0];
		if(buff[0] == ZMIPC_ACT_SET)
		{
			content->alarm_params_operation.snapshot_params.flag = buff[1];
			content->alarm_params_operation.snapshot_params.pics_num = buff[2]|(buff[3]<<8);
			content->alarm_params_operation.snapshot_params.interval_time = buff[4];
		}
		break;
	case SOCKET_SET_ALARM_IO:			//0xAD
		content->alarm_params_operation.io_params.down_action = buff[0];
		if(buff[0] == ZMIPC_ACT_SET)
		{
			content->alarm_params_operation.io_params.flag = buff[1];
			content->alarm_params_operation.io_params.trig_level = buff[2];
		}
		break;

		case SOCKET_REBOOT:					//0xAE
			content->reboot_device_dummy = buff[0];// reserved
			break;
		case SOCKET_EMAIL_TEST:				//0xAF
			content->test_mail_dummy = buff[0];// reserved
			break;
		case SOCKET_SET_CODE:				//0xB0
			memcpy(content->change_password,buff,len);
			break;
		case SOCKET_GET_NATTYPE:			//0xB1 -- to stun server
			buff[len] = 0;// ensure string ends with null byte
			sscanf(buff,"%[^;];%s",content->get_nat_type.id,content->get_nat_type.stun_domain);
			buff[len] = ck_sum;/// restore checksum
			break;

		case SOCKET_SET_DISPALY:			// 0xB2 -- set display information 
			memcpy(content->dev_display_info,buff,len);
			break;

		case SOCKET_IO_CONTROL:				// 0xB3 -- IO control cmd
			content->io_control_cmd = buff[0]|(buff[1]<<8);
			break;

		case SOCKET_MINOR_STREAM:			//0xB4 
			content->minor_stream_level.action = buff[0];
			content->minor_stream_level.level = buff[1];
			break;
			/*
			 * // register reponse cmd, in p2p protocol 
			 * case SOCKET_SET_SERVERINFO	    //0xD3 
			 */
		case SOCKET_GET_PASSWD:				//0xD7 // unkown
			// do nothing
			break;
		case SOCKET_SDCARD_VALUE:			//0xFFA0 //lhq add
			content->sdcard_params_operation.down_action= buff[0];
			if(buff[0] == ZMIPC_ACT_SET)
			{
				content->sdcard_params_operation.umount_flag = buff[1];
				//content->sdcard_params_operation.free_space = buff[2];
				//content->sdcard_params_operation.total_space = buff[3];
			}
			break;
		case SOCKET_DEV_VERSION:
			content->sdcard_params_operation.down_action= buff[0];
			// do nothing
			break;
			
		case SOCKET_SET_WIFI_IN_AP:
			memset(&content->wifi_params_ap, 0, sizeof(struct wifi_params_ap));
			content->wifi_params_ap.type = buff[0];
			j = 1;
			for(i = 0; ((i+j) < len)&&(buff[i+j] != 0x20); i++) {
				content->wifi_params_ap.ssid[i] = buff[i+j];
			}
			j += i;
			j++;
			for(i = 0; (i+j) < len; i++)
				content->wifi_params_ap.pwd[i] = buff[i+j];
			SLOG(TDBG, "ap_wifi type:%d\n", content->wifi_params_ap.type);
			SLOG(TDBG, "ap_wifi ssid:%s\n", content->wifi_params_ap.ssid);
			SLOG(TDBG, "ap_wifi pwd:%s\n", content->wifi_params_ap.pwd);
			break;

		default:
			ret = VPI_EFAIL;
			break;
	}

    return ret;
}

int zmipc_build_package(eproto_role role, sproto_msg *pmsg, unsigned char *sendbuff, int *len)
{
    int ret = 0;
    unsigned char buf_tmp[512] = {0};
    int tmplen = 512;
    unsigned int cmd = pmsg->cmd;
    szmipc_content *content = (szmipc_content *)pmsg->content;
	unsigned char *tmpbuf = &buf_tmp[0];

    if(content == NULL || sendbuff == NULL || len == NULL)
    {
        PLOG(ERR, "invalid params!\n");
        return VPI_EPARAMS;
    }

	if(*len >= tmplen)
	{
		tmpbuf = sendbuff;
		tmplen = *len;
	}

    if(IS_ZMIPC_UPCMD(cmd) && role==ROLE_DEV)
    {
        tmpbuf[0] = ZMIPC_TOP_1;
        tmpbuf[1] = ZMIPC_TOP_2;
        tmpbuf[2] = tmpbuf[3] = 0xff;// the pack length not data length, little endian
		if(((cmd>>8)&0xff) == 0xff) {
			tmpbuf[4] = (cmd>>8) & 0xff;
			tmpbuf[5] = cmd & 0xff;
			tmplen -= 8;// 5+checksum+end
			ret = build_up_package(cmd, &content->up_content, tmpbuf + 6, &tmplen);
			if(ret == 0)
			{
				tmplen += 8;
				tmpbuf[2] = tmplen & 0xff;
				tmpbuf[3] = (tmplen >> 8) & 0xff;
				if(cmd == SOCKET_RES_DATA) { 
					tmpbuf[tmplen - 2] = 0x00;//vpi_calc_checksum(tmpbuf, tmplen - 2);
				} else {
					tmpbuf[tmplen - 2] = vpi_calc_checksum(tmpbuf, tmplen - 2);
				}
				tmpbuf[tmplen - 1] = ZMIPC_END;
			}
			int i;
			SLOG(TDBG, "uuuuuuuuuuuuuuuuuuuuuuuuuuun\n");
			for(i = 0; i < tmplen; i++) 
				printf("0x%x ", tmpbuf[i]);
			printf("\n");
		} else {
			tmpbuf[4] = cmd & 0xff;
			tmplen -= 7;// 5+checksum+end
			ret = build_up_package(cmd, &content->up_content, tmpbuf + 5, &tmplen);
			if(ret == 0)
			{
				tmplen += 7;
				tmpbuf[2] = tmplen & 0xff;
				tmpbuf[3] = (tmplen >> 8) & 0xff;
				if(cmd == SOCKET_RES_DATA) { 
					tmpbuf[tmplen - 2] = 0x00;//vpi_calc_checksum(tmpbuf, tmplen - 2);
				} else {
					tmpbuf[tmplen - 2] = vpi_calc_checksum(tmpbuf, tmplen - 2);
				}
				tmpbuf[tmplen - 1] = ZMIPC_END;
			}
		}
	}
    else if(IS_ZMIPC_DOWNCMD(cmd) && role==ROLE_SERVER)
    {
        tmpbuf[0] = ZMIPC_TOP_1;
        tmpbuf[1] = ZMIPC_TOP_2;
        tmpbuf[2] = tmpbuf[3] = 0xff;// data length
		if(((cmd >> 8)&0xff) == 0xFF){
	        tmpbuf[5] = cmd & 0xff;
			tmpbuf[4] = (cmd >> 8) & 0xff;
	        tmplen -= 8;// 6+checksum+end
			ret = build_down_package(cmd, &content->down_content, tmpbuf + 6, &tmplen);	
	        if(ret == 0)
	        {
	            tmplen += 8;
	            tmpbuf[2] = tmplen & 0xff;
	            tmpbuf[3] = (tmplen >> 8) & 0xff;
	            tmpbuf[tmplen - 2] = vpi_calc_checksum(tmpbuf, tmplen - 2);
	            tmpbuf[tmplen - 1] = ZMIPC_END;
	        }
		}else{        
        tmpbuf[4] = cmd & 0xff;
        tmplen -= 7;// 5+checksum+end
        ret = build_down_package(cmd, &content->down_content, tmpbuf + 5, &tmplen);

        if(ret == 0)
        {
            tmplen += 7;
            tmpbuf[2] = tmplen & 0xff;
            tmpbuf[3] = (tmplen >> 8) & 0xff;
			tmpbuf[tmplen - 2] = vpi_calc_checksum(tmpbuf, tmplen - 2);
            tmpbuf[tmplen - 1] = ZMIPC_END;
	        }
        }
    }
    else
    {
        PLOG(ERR, "cmd 0x%x and role %d is unsupported!\n", cmd, role);
        return VPI_EFAIL;
    }

    if(!ret && *len >= tmplen)
    {
        // buff is enough big
        //PLOG(DBG, "send buff len = %d.\n", tmplen);
		if(tmpbuf != sendbuff)
		{
			memset(sendbuff, 0, *len);
			memcpy(sendbuff, tmpbuf, tmplen);
		}
		*len = tmplen;
		vpi_print_package(sendbuff, *len);
    }
    else if(!ret && *len < tmplen)
    {
        PLOG(ERR, "send buff is not enough,%d < %d[need]\n", *len, tmplen);
        ret = VPI_ESPACE;
    }

    return ret;
}

int zmipc_parse_package(eproto_role role, sproto_msg *pmsg, unsigned char *recvbuff, int len)
{
    unsigned int *cmd = &pmsg->cmd;
    szmipc_content *content = (szmipc_content *)pmsg->content;
    int data_len = 0;
    int ret = 0;
    unsigned char expected_res_cmd = 0x00;

    if(content == NULL || recvbuff == NULL || len <= 0)
    {
        PLOG(ERR, "invalid params!\n");
        return VPI_EPARAMS;
    }

    vpi_print_package(recvbuff, len);

    if(role == ROLE_DEV)
    {
        if(recvbuff[0] != ZMIPC_TOP_1 || recvbuff[1] != ZMIPC_TOP_2 ||
                recvbuff[len - 1] != ZMIPC_END)
        {
            PLOG(ERR, "recv package is invalid in device role.\n");
            ret = VPI_EFORMAT;
        }
        else if(recvbuff[len - 2] != vpi_calc_checksum(recvbuff, len - 2))
        {
            PLOG(ERR, "recv package checksum error!\n");
            ret = VPI_ECHECKSUM;
        }
        else if(IS_ZMIPC_UPCMD(*cmd) && // valid current send cmd
                (expected_res_cmd = expected_response_cmd(*cmd)) != 0x00 &&
                recvbuff[4] != expected_res_cmd) // response cmd ok
        {
            PLOG(ERR, "recv cmd 0x%02x is not respond to send cmd 0x%02x\n", recvbuff[4], *cmd);
            ret = VPI_ERESPCMD;
        }
        else
        {
            PLOG(DBG, "recv server ok,parse the content...\n");
			if(recvbuff[4] == 0xff) {
				*cmd = recvbuff[5] | (recvbuff[4] << 8);
				data_len = recvbuff[2] + (recvbuff[3] << 8) - 8; // fixed bytes is 8 
				if(data_len > 0) // have params
					ret = parse_down_package(*cmd, &content->down_content, recvbuff + 6, data_len);
			} else {
				*cmd = recvbuff[4];
				data_len = recvbuff[2] + (recvbuff[3] << 8) - 7; // fixed bytes is 7
				if(data_len > 0) // have params
					ret = parse_down_package(*cmd, &content->down_content, recvbuff + 5, data_len);
			}
        }
    }
    else if(role == ROLE_SERVER)
    {
        if(recvbuff[0] != ZMIPC_TOP_1 || recvbuff[1] != ZMIPC_TOP_2 ||
                recvbuff[len - 1] != ZMIPC_END)
        {
            PLOG(ERR, "recv package is invalid in server role.\n");
            ret = VPI_EFORMAT;
        }
        else if(recvbuff[len - 2] != vpi_calc_checksum(recvbuff, len - 2))
        {
            PLOG(ERR, "recv package checksum error!\n");
            ret = VPI_ECHECKSUM;
        }
        else if(IS_ZMIPC_DOWNCMD(*cmd) &&
                (expected_res_cmd = expected_response_cmd(*cmd)) != 0x00 &&
                recvbuff[4] != expected_res_cmd) // response cmd ok
        {
            PLOG(ERR, "recv cmd 0x%02x is not respond to send cmd 0x%02x\n", recvbuff[4], *cmd);
            ret = VPI_ERESPCMD;
        }
        else
        {
			if(recvbuff[4] == 0xFF) {
				*cmd = recvbuff[5] | (recvbuff[4] << 8);
				data_len = recvbuff[2] + (recvbuff[3] << 8) - 8; // pack len - fixed bytes
	            if(data_len > 0) // have params
	                ret = parse_up_package(*cmd, &content->up_content, recvbuff + 6, data_len);				
			} else { //lhq
            PLOG(DBG, "recv device ok,parse the content...\n");
            *cmd = recvbuff[4];
            data_len = recvbuff[2] + (recvbuff[3] << 8) - 7; // pack len - fixed bytes
            PLOG(DBG, "recv cmd = 0x%02x, data len = %d\n", *cmd, data_len);

            if(data_len > 0) // have params
                ret = parse_up_package(*cmd, &content->up_content, recvbuff + 5, data_len);
			}
        }
    }
    else
    {
        PLOG(ERR, "role %d or cmd 0x%x is unsupported!\n", role, *cmd);
        ret = VPI_EFAIL;
    }

    return ret;
}

int pack_raw_stream_data(unsigned char type,unsigned long long timestamp,unsigned char frame_seq,unsigned char *data,unsigned short len, unsigned char *desbuff, int deslen)
{
	if(type != ZMIPC_DT_VIDEO && type != ZMIPC_DT_AUDIO 
		&& type != ZMIPC_DT_VAMIX && type != ZMIPC_DT_MINOR)
	{
		PLOG(ERR,"type = %d is invalid.\n",type);
		return VPI_EPARAMS;
	}
	if(data == NULL || desbuff == NULL || len <= 0 || deslen <= len)
	{
		PLOG(ERR,"data/desbuff is NULL,or len = %d,deslen = %d.\n",len,deslen);
		return VPI_EPARAMS;
	}

	int ret = 0;
	sproto_msg msg;
    szmipc_content zmipc_content;
	struct up_data_transfer *up_data = &zmipc_content.up_content.data_transfer;
    msg.cmd = SOCKET_RES_DATA; 
    msg.length = sizeof(szmipc_content);
    msg.content = &zmipc_content;
    memset(&zmipc_content, 0, sizeof(szmipc_content));
	
	up_data->res_data.type = type;
	up_data->res_data.timestamp = timestamp;
	up_data->res_data.frame_seq = frame_seq;
	up_data->res_data.data = data;
	up_data->res_data.len = len;

	ret = zmipc_build_package(ROLE_DEV,&msg,desbuff,&deslen);	
	//vpi_print_package(desbuff,15);
	if(ret == VPI_SUCCESS)
		return deslen;
	else
		return ret;
}

int pack_active_alarm_status(unsigned char seq, unsigned char type, unsigned char extra,unsigned char *desbuff, int deslen)
{
	if(desbuff == NULL)
	{
		PLOG(ERR,"invalid params\n");
		return VPI_EPARAMS;
	}

	int ret = 0;
	sproto_msg msg;
    szmipc_content zmipc_content;
	struct active_alarm_status *up_data = &zmipc_content.up_content.active_alarm_status;
    msg.cmd = SOCKET_REPORT_ALARM_STATUS; 
    msg.length = sizeof(szmipc_content);
    msg.content = &zmipc_content;
    memset(&zmipc_content, 0, sizeof(szmipc_content));

	up_data->seq = seq;
	up_data->status = type;
	up_data->extra_stat = extra;

	ret = zmipc_build_package(ROLE_DEV,&msg,desbuff,&deslen);	

	if(ret == VPI_SUCCESS)
		return deslen;
	else
		return ret;
}

